﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Web.UI.HtmlControls;
using System.Text;

namespace BEELab
{
    public partial class EditSession : System.Web.UI.Page
    {
        #region members
        DataTable result = new DataTable();
        private DataTable SessionValues;
        #endregion
        
        /// <summary>
        /// Occures on every page load (first time or Post Back)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.QueryString["ID"] != null && Session["UserID"] != null && BEELab.Logic.ProgramManagement.SessionManagement.SessionManagement.GetOwnerID(int.Parse(Request.QueryString["ID"].ToString())) != int.Parse(Session["UserID"].ToString()) && (Session["Admin"] == null || (bool)Session["Admin"] == false))
            {
                Response.Redirect("Main.aspx");
            }

            if (!IsPostBack)
            {
                if (Request.QueryString["ID"] != null)
                {
                    txtName.Text = BEELab.Logic.ProgramManagement.SessionManagement.SessionManagement.GetName(int.Parse(Request.QueryString["ID"].ToString()));
                    txtDescription.Text = BEELab.Logic.ProgramManagement.SessionManagement.SessionManagement.GetDescription(int.Parse(Request.QueryString["ID"].ToString()));

                    if (Global.BlockElementsDictionary.ContainsKey(int.Parse(Request.QueryString["ID"].ToString())))
                    {
                        lblStatus.Text = "Active";
                        lnkActive.Visible = false;
                        lnkdeactive.Visible = true;
                        LiveDataLink.Text = "<a href='javascript:void(0);' onclick='popitup(\"LiveData.aspx?ID=" + Request.QueryString["ID"].ToString() + "\");'>-Live Session Data-</a>";
                    }
                    else
                    {
                        lblStatus.Text = "Inactive";
                        lnkActive.Visible = true;
                        lnkdeactive.Visible = false;
                        LiveDataLink.Text = "";
                    }

                    FillVariables();
                }
            }

            if (Request.QueryString["ID"] != null)
            {
                SqlCommand command = new SqlCommand();
                command.CommandText = "SELECT SubjectID, Label, Value FROM RecordedData JOIN Subjects ON Subjects.ID=RecordedData.SubjectID WHERE Subjects.SessionID=@SessionID";
                command.Parameters.Add(new SqlParameter("@SessionID", int.Parse(Request.QueryString["ID"].ToString())));
                DataTable data = BEELab.Data.DBHelper.ExecuteQuery(command);

                command = new SqlCommand();
                command.CommandText = "SELECT ID FROM Subjects WHERE SessionID=@SessionID";
                command.Parameters.Add(new SqlParameter("@SessionID", int.Parse(Request.QueryString["ID"].ToString())));
                DataTable subjectIDs = BEELab.Data.DBHelper.ExecuteQuery(command);

                result.Columns.Add("SubjectID");
                

                DataRow newRow;
                DataRow[] rows;

                foreach (DataRow row in subjectIDs.Rows)
                {
                    rows = data.Select("SubjectID='" + row["ID"].ToString() + "'");
                    foreach (DataRow element in rows)
                    {
                        if (!result.Columns.Contains(element["Label"].ToString()))
                        {
                            result.Columns.Add(element["Label"].ToString());
                        }
                    }

                    newRow = result.NewRow();
                    newRow["SubjectID"] = row["ID"].ToString();
                    foreach (DataRow element in rows)
                    {
                        newRow[element["Label"].ToString()] = element["Value"].ToString();
                    }

                    result.Rows.Add(newRow);
                }

                GridView1.DataSource = result;
                GridView1.DataBind();
            }
        }

        /// <summary>
        /// Gets all variables and their values that belongs to this Session of experiment, and present it to user.
        /// </summary>
        private void FillVariables()
        {
            //Gets ProgramID according to SessionID
            int ProgramID = BEELab.Logic.ProgramManagement.SessionManagement.SessionManagement.GetProgramIDBySessionID(int.Parse(Request.QueryString["ID"].ToString()));

            //Get ALL variables related to this program, insert in to DataTable
            SqlCommand command = new SqlCommand();
            command.CommandText = "SELECT * FROM Variables WHERE ProgramID=@ProgramID";
            command.Parameters.Add(new SqlParameter("@ProgramID", ProgramID));
            DataTable AllVariables = BEELab.Data.DBHelper.ExecuteQuery(command);

            //Gets first stage and insert it to AllVariables DataTable
            DataRow newRow = AllVariables.NewRow();
            newRow["ID"] = 0;
            newRow["Name"] = "First Stage";
            newRow["Scope"] = "Subject";
            newRow["DefaultValue"] = BEELab.Logic.ProgramManagement.SessionManagement.SessionManagement.GetFirstStage(int.Parse(Request.QueryString["ID"].ToString()));
            AllVariables.Rows.InsertAt(newRow, 0);

            //Fill in SessionValues DataTable with variables that belongs to session only
            command.CommandText = "SELECT VariableID, Value FROM InitialValues WHERE ParentID=@SessionID AND Type='Session'";
            command.Parameters.Add(new SqlParameter("@SessionID", int.Parse(Request.QueryString["ID"].ToString())));
            SessionValues = BEELab.Data.DBHelper.ExecuteQuery(command);

            //Bind between AllVariables DataTable and the GUI
            rptSessionVariable.DataSource = AllVariables;
            rptSessionVariable.DataBind();
        }

        /// <summary>
        /// Occures when pressing "back" button on a session page - returns beck to relevant experiment page
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void BackToExperiment_Click(object sender, EventArgs e)
        {
            SqlCommand command = new SqlCommand();
            command.CommandText = "SELECT ProgramID FROM Sessions WHERE ID=@StageID";
            command.Parameters.Add(new SqlParameter("@StageID", int.Parse(Request.QueryString["ID"].ToString())));
            DataTable dt = BEELab.Data.DBHelper.ExecuteQuery(command);
            if (dt != null)
            {
                String ProgramID = dt.Rows[0]["ProgramID"].ToString();
                Response.Redirect("EditExperiment.aspx?ID=" + ProgramID);
            }
        }

        /// <summary>
        /// Raises an event once one of the values of the variables on the page changes by the user.
        /// Occurs after an item in the Repeater control is data-bound but before it is rendered on the page.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void rptSessionVariable_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            var item = (DataRowView)e.Item.DataItem;
            var tValue = ((TextBox)e.Item.FindControl("txtVariable"));
            var oldValue = ((Label)e.Item.FindControl("lblOldValue"));

            DataRow[] foundRows = SessionValues.Select("VariableID=" + item["ID"].ToString());

            if (foundRows.Length > 0)
            {
                tValue.Text = foundRows[0]["Value"].ToString();
            }
            else
            {
                tValue.Text = item["DefaultValue"].ToString();
            }

            oldValue.Text = tValue.Text;
        }

        /// <summary>
        /// Occures once the user press on Submit button in order
        /// to save session new values or on Activate session button.
        /// Updates all variables values for this session on DB.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            BEELab.Logic.ProgramManagement.SessionManagement.SessionManagement.UpdateSession(int.Parse(Request.QueryString["ID"].ToString()), txtName.Text, txtDescription.Text);

            foreach (RepeaterItem item in rptSessionVariable.Items)
            {
                if (((Label)item.FindControl("lblOldValue")).Text != ((TextBox)item.FindControl("txtVariable")).Text)
                {
                    BEELab.Logic.ProgramManagement.SessionManagement.SessionManagement.SetVariableValue(int.Parse(Request.QueryString["ID"].ToString()), int.Parse(((Label)item.FindControl("lblVariableId")).Text), ((TextBox)item.FindControl("txtVariable")).Text);
                }
            }
        }

        /// <summary>
        /// Creates new invitation to current session.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Button1_Click(object sender, EventArgs e)
        {
            BEELab.Logic.ProgramManagement.SessionManagement.InvitationManagement.CreateInvitation(int.Parse(Request.QueryString["ID"].ToString()), TextBox1.Text);
            TextBox1.Text = "";
            gvInvitation.DataBind();
        }

        /// <summary>
        /// Occures once the user press on "activate" button in order make session active.
        /// Updates all variables values for this session on DB and updates GUI.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void lnkActive_Click(object sender, EventArgs e)
        {
            Logic.Execution.Execute.EstablishSession(int.Parse(Request.QueryString["ID"].ToString()));
            lblStatus.Text = "Active";
            lnkActive.Visible = false;
            lnkdeactive.Visible = true;
            LiveDataLink.Text = "<a href='javascript:void(0);' onclick='popitup(\"LiveData.aspx?ID=" + Request.QueryString["ID"].ToString() + "\");'>-Live Session Data-</a>";

            btnSubmit_Click(sender, e);
        }

        /// <summary>
        /// Occures once the user press on Deactivate button of a session.
        /// Updates GUI and updates that session is in in-active mode.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void lnkdeactive_Click(object sender, EventArgs e)
        {
            Global.BlockElementsDictionary.Remove(int.Parse(Request.QueryString["ID"].ToString()));
            Global.PresentationElementsDictionary.Remove(int.Parse(Request.QueryString["ID"].ToString()));
            Global.DataElementsDictionary.Remove(int.Parse(Request.QueryString["ID"].ToString()));
            Global.VariableIDNameDictionary.Remove(int.Parse(Request.QueryString["ID"].ToString()));
            Global.SessionVariables.Remove(int.Parse(Request.QueryString["ID"].ToString()));
            Global.VariableScopeDictionary.Remove(int.Parse(Request.QueryString["ID"].ToString()));

            foreach (string subject in BEELab.Logic.ProgramManagement.SessionManagement.SessionManagement.GetSubjectList(int.Parse(Request.QueryString["ID"].ToString())))
            {
                if (Global.MessageBox.ContainsKey(subject))
                {
                    Global.MessageBox.Remove(subject);
                }

                if (Global.SubjectConnetionDictionary.ContainsKey(subject))
                {
                    Global.SubjectConnetionDictionary.Remove(subject);
                }

                if (Global.SubjectVariables.ContainsKey(subject))
                {
                    Global.SubjectVariables.Remove(subject);
                }
            }

            lblStatus.Text = "Inactive";
            lnkActive.Visible = true;
            lnkdeactive.Visible = false;
            LiveDataLink.Text = "";

            Logic.Execution.SessionRecovery.DropSession(int.Parse(Request.QueryString["ID"].ToString()));
        }

        /// <summary>
        /// Occures when the user clicks on "Download Data" button in order to save log file with 
        /// experiment results. 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnExportCSV_Click(object sender, EventArgs e)
        {
            Response.Clear();
            Response.Buffer = true;
            Response.AddHeader("content-disposition",
             "attachment;filename=SessionData.csv");
            Response.Charset = "";
            Response.ContentType = "application/text";

            //GridView1.AllowPaging = false;
            //GridView1.DataBind();

            StringBuilder sb = new StringBuilder();
            for (int k = 0; k < result.Columns.Count; k++)
            {
                //add separator
                sb.Append(result.Columns[k].ColumnName + ',');
            }
            //append new line
            sb.Append("\r\n");
            for (int i = 0; i < result.Rows.Count; i++)
            {
                for (int k = 0; k < result.Columns.Count; k++)
                {
                    //add separator
                    sb.Append('"' + result.Rows[i][k].ToString().Replace("\"", "\"\"") + '"' + ',');
                }
                //append new line
                sb.Append("\r\n");
            }
            Response.Output.Write(sb.ToString());
            Response.Flush();
            Response.End();
        }

        /// <summary>
        /// Updates details of current running Session on GUI
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
                HyperLink link = new HyperLink();
                link.Text = e.Row.Cells[0].Text;
                link.NavigateUrl = "./Logic/Execution/Execute.aspx?SubjectID=" + e.Row.Cells[0].Text;
                link.Target = "_blank";
                e.Row.Cells[0].Controls.Add(link);
            }
        }
    }
}